home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / quicktime vr / vrbackbuffer / common files / qtutilities.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  52.6 KB  |  1,873 lines

  1. //////////
  2. //
  3. //    File:        QTUtilities.c
  4. //
  5. //    Contains:    Some utilities for working with QuickTime movies.
  6. //                All utilities start with the prefix "QTUtils_".
  7. //
  8. //    Written by:    Tim Monroe
  9. //                Based on the DTSQTUtilities package by Apple DTS.
  10. //                This began as essentially a subset of that package, revised for cross-platform use.
  11. //
  12. //    Copyright:    © 1996-1999 by Apple Computer, Inc., all rights reserved.
  13. //
  14. //    Change History (most recent first):
  15. //
  16. //       <25>         05/19/99    rtm        removed QTUtils_GetMovie
  17. //       <24>         05/10/99    rtm        added QTUtils_UpdateMovieVolumeSetting
  18. //       <23>         03/22/99    rtm        updated connection speed code to use constants/data types now in Movies.h
  19. //       <22>         03/11/99    rtm        moved _GetControllerType and _SetControllerType from QTVRUtilities to here;
  20. //                                    added QTUtils_ChangeControllerType
  21. //       <21>         02/03/99    rtm        moved non-QTVR-specific utilities from QTVRUtilities to here
  22. //       <20>         01/26/99    rtm        added QTUtils_ConvertCToPascalString; removed "\p" from any constant strings
  23. //       <19>         01/25/99    rtm        #define'd away QTUtils_GetUsersContentRating and siblings, since content rating
  24. //                                    capability is not in latest feature set
  25. //       <18>         12/09/98    rtm        added QTUtils_GetUsersContentRating
  26. //       <17>         11/18/98    rtm        added QTUtils_GetFrameCount
  27. //       <16>         10/27/98    rtm        added QTUtils_MakeMovieLoop
  28. //       <15>         09/14/98    rtm        added QTUtils_GetUsersConnectionSpeed and QTUtils_SetUsersConnectionSpeed
  29. //       <14>         06/24/98    rtm        added QTUtils_GetMaxWindowDepth and QTUtils_GetMaxScreenDepth
  30. //       <13>         06/04/98    rtm        added QTUtils_DeleteAllReferencesToTrack
  31. //       <12>         05/28/98    rtm        added some typecasting to minimize MSDev compiler warnings
  32. //       <11>         05/19/98    rtm        added QTUtils_MovieHasTimeCodeTrack
  33. //       <10>         05/04/98    rtm        added QTUtils_GetTrackName, QTUtils_SetTrackName, QTUtils_MakeTrackNameByType,
  34. //                                    QTUtils_IsImageFile, and QTUtils_IsMovieFile
  35. //       <9>         02/28/98    rtm        fixed QTUtils_GetMovieFileLoopingInfo and the like
  36. //       <8>         01/14/98    rtm        added QTUtils_ConvertFloatToBigEndian
  37. //       <7>         12/19/97    rtm        added QTUtils_AddUserDataTextToMovie and associated routines;
  38. //                                    added QTUtils_GetMovieFileLoopingInfo and the like
  39. //       <6>         11/06/97    rtm        added QTUtils_MakeSampleDescription
  40. //       <5>         10/29/97    rtm        modified QTUtils_IsMediaTypeInMovie and similar routines to use GetMovieIndTrackType
  41. //       <4>         10/27/97    rtm        added QTUtils_HasQuickTimeVideoEffects
  42. //       <3>         10/17/97    rtm        added QTUtils_MovieHasSoundTrack
  43. //       <2>         09/23/97    rtm        added endian adjustment to QTUtils_PrintMoviePICT
  44. //       <1>         09/10/97    rtm        first file
  45. //       
  46. //////////
  47.  
  48. //////////
  49. //
  50. // header files
  51. //
  52. //////////
  53.  
  54. #ifndef __QTUtilities__
  55. #include "QTUtilities.h"
  56.  
  57.  
  58. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. //
  60. // General utilities.
  61. //
  62. // Use these functions to get information about the availability/features of QuickTime or other services.
  63. //
  64. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  65.  
  66. //////////
  67. //
  68. // QTUtils_TrapAvailable
  69. // Check to see whether a given trap is implemented. This is based on IM: Operating System Utilities (p. 8-22).
  70. //
  71. //////////
  72.  
  73. #if TARGET_OS_MAC
  74. Boolean QTUtils_TrapAvailable (short theTrapWord)
  75. {
  76.     TrapType        myTrapType;
  77.     short            myNumToolboxTraps;
  78.     
  79.     // determine whether this is a Toolbox or an Operating System trap
  80.     if ((theTrapWord & 0x0800) > 0)
  81.         myTrapType = ToolTrap;
  82.     else
  83.         myTrapType = OSTrap;
  84.  
  85.     if (myTrapType == ToolTrap) {
  86.         theTrapWord = theTrapWord & 0x07FF;
  87.         
  88.         if (NGetTrapAddress(_InitGraf, ToolTrap) == NGetTrapAddress(0xAA6E, ToolTrap))
  89.             myNumToolboxTraps = 0x0200;
  90.         else
  91.             myNumToolboxTraps = 0x0400;
  92.             
  93.         if (theTrapWord >= myNumToolboxTraps)
  94.             theTrapWord = _Unimplemented;
  95.     }
  96.  
  97.     return(NGetTrapAddress(theTrapWord, myTrapType) != NGetTrapAddress(_Unimplemented, ToolTrap));
  98. }
  99. #endif
  100.  
  101.  
  102. //////////
  103. //
  104. // QTUtils_IsQuickTimeInstalled
  105. // Is QuickTime installed?
  106. //
  107. //////////
  108.  
  109. Boolean QTUtils_IsQuickTimeInstalled (void) 
  110. {
  111.     Boolean     myQTAvail = false;
  112.     long        myAttrs;
  113.     OSErr         myErr = noErr;
  114.  
  115.     myErr = Gestalt(gestaltQuickTime, &myAttrs);
  116.     if (myErr == noErr)
  117.         myQTAvail = true;
  118.  
  119.     return(myQTAvail);
  120. }
  121.  
  122.  
  123. //////////
  124. //
  125. // QTUtils_IsQuickTimeCFMInstalled
  126. // Are the QuickTime CFM libraries installed?
  127. //
  128. //////////
  129.  
  130. #if TARGET_OS_MAC
  131. #ifdef powerc
  132. Boolean QTUtils_IsQuickTimeCFMInstalled (void) 
  133. {
  134.     Boolean     myQTCFMAvail = false;
  135.     long        myAttrs;
  136.     OSErr         myErr = noErr;
  137.  
  138.     // test whether the library is registered.
  139.     myErr = Gestalt(gestaltQuickTimeFeatures, &myAttrs);
  140.     if (myErr == noErr)
  141.         if (myAttrs & (1L << gestaltPPCQuickTimeLibPresent))
  142.             myQTCFMAvail = true;
  143.  
  144.     // test whether a function is available (the library is not moved from the Extension folder);
  145.     // this is the trick to be used when testing if a function is available via CFM
  146.     if (!CompressImage)
  147.         myQTCFMAvail = false;     
  148.  
  149.     return(myQTCFMAvail);
  150. }
  151. #endif    // powerc
  152. #endif
  153.  
  154.  
  155. //////////
  156. //
  157. // QTUtils_GetQTVersion
  158. // Get the version of QuickTime installed.
  159. // The high-order word of the returned long integer contains the version number,
  160. // so you can test a version like this:
  161. //
  162. //        if (((QTUtils_GetQTVersion() >> 16) & 0xffff) >= 0x0210)        // we require QT 2.1 or greater
  163. //            return;
  164. //
  165. //////////
  166.  
  167. long QTUtils_GetQTVersion (void) 
  168. {
  169.     long         myVersion = 0L;
  170.     OSErr         myErr = noErr;
  171.  
  172.     myErr = Gestalt(gestaltQuickTime, &myVersion);
  173.     if (myErr == noErr)
  174.         return(myVersion);
  175.     else
  176.         return(0L);
  177. }
  178.  
  179.  
  180. //////////
  181. //
  182. // QTUtils_HasQuickTimeVideoEffects
  183. // Does the installed version of QuickTime support video effects?
  184. //
  185. // Note: this is a pretty cheesy way of determining whether video effects are available.
  186. //
  187. //////////
  188.  
  189. Boolean QTUtils_HasQuickTimeVideoEffects (void) 
  190. {
  191.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTVideoEffectsMinVers);
  192. }
  193.  
  194.  
  195. //////////
  196. //
  197. // QTUtils_HasFullScreenSupport
  198. // Does the installed version of QuickTime support the full-screen routines?
  199. //
  200. // Note: this is a pretty cheesy way of determining whether full-screen routines are available.
  201. //
  202. //////////
  203.  
  204. Boolean QTUtils_HasFullScreenSupport (void) 
  205. {
  206.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTFullScreenMinVers);
  207. }
  208.  
  209.  
  210. //////////
  211. //
  212. // QTUtils_HasWiredSprites
  213. // Does the installed version of QuickTime support wired sprites?
  214. //
  215. // Note: this is a pretty cheesy way of determining whether wired sprites are available.
  216. //
  217. //////////
  218.  
  219. Boolean QTUtils_HasWiredSprites (void) 
  220. {
  221.     return(((QTUtils_GetQTVersion() >> 16) & 0xffff) >= kQTWiredSpritesMinVers);
  222. }
  223.  
  224.  
  225. //////////
  226. //
  227. // QTUtils_IsStreamedMovie
  228. // Is the specified movie a streamed movie?
  229. //
  230. //////////
  231.  
  232. Boolean QTUtils_IsStreamedMovie (Movie theMovie) 
  233. {
  234.     return(GetMovieIndTrackType(theMovie, 1, kQTSStreamMediaType, movieTrackMediaType | movieTrackEnabledOnly) != NULL);
  235. }
  236.  
  237.  
  238. //////////
  239. //
  240. // QTUtils_SaveMovie
  241. // Save and flatten a movie resource into a file.
  242. //
  243. //////////
  244.  
  245. OSErr QTUtils_SaveMovie (Movie theMovie)
  246. {
  247.     StandardFileReply    mySFReply;
  248.     StringPtr             myPrompt = QTUtils_ConvertCToPascalString(kSavePrompt);
  249.     StringPtr             myFileName = QTUtils_ConvertCToPascalString(kSaveMovieFileName);
  250.     OSErr                myErr = noErr;
  251.     
  252.     if (theMovie == NULL)
  253.         return(invalidMovie);
  254.     
  255.     StandardPutFile(myPrompt, myFileName, &mySFReply); 
  256.     if (mySFReply.sfGood) {
  257.         FlattenMovieData(theMovie, flattenAddMovieToDataFork, &mySFReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, createMovieFileDeleteCurFile);
  258.         myErr = GetMoviesError();
  259.     }
  260.  
  261.     free(myPrompt);
  262.     free(myFileName);
  263.     
  264.     return(myErr);
  265. }
  266.  
  267.  
  268. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  269. //
  270. // Controller bar utilities.
  271. //
  272. // Use these functions to manipulate the controller bar, its buttons, and the help text displayed in it.
  273. //
  274. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  275.  
  276. //////////
  277. //
  278. // QTUtils_IsControllerBarVisible
  279. // Is the controller bar currently visible?
  280. //
  281. //////////
  282.  
  283. Boolean QTUtils_IsControllerBarVisible (MovieController theMC) 
  284. {
  285.     return((Boolean)MCGetVisible(theMC));
  286. }
  287.  
  288.  
  289. //////////
  290. //
  291. // QTUtils_GetControllerBarHeight
  292. // Return the height of the controller bar displayed by the movie controller.
  293. //
  294. // Note that MCGetControllerBoundsRect returns rectangle of bar and movie, if attached;
  295. // so we need to unattach the controller bar first.
  296. //
  297. //////////
  298.  
  299. short QTUtils_GetControllerBarHeight (MovieController theMC) 
  300. {
  301.     Boolean        wasAttached = false;
  302.     Rect        myRect;
  303.     short        myHeight = 0;
  304.     
  305.     // if the controller bar is attached, detach it (and remember we did so)
  306.     if (MCIsControllerAttached(theMC) == 1) {
  307.         wasAttached = true;
  308.         MCSetControllerAttached(theMC, false);
  309.     }
  310.     
  311.     // get the rectangle of the controller
  312.     MCGetControllerBoundsRect(theMC, &myRect);
  313.     myHeight = myRect.bottom - myRect.top;
  314.     
  315.     // now reattach the controller bar, if it was originally attached
  316.     if (wasAttached)
  317.         MCSetControllerAttached(theMC, true);
  318.     
  319.     return(myHeight);
  320. }
  321.  
  322.  
  323. //////////
  324. //
  325. // QTUtils_HideControllerBar
  326. // Hide the controller bar provided by the movie controller.
  327. //
  328. //////////
  329.  
  330. void QTUtils_HideControllerBar (MovieController theMC) 
  331. {
  332.     MCSetVisible(theMC, false);
  333. }
  334.  
  335.  
  336. //////////
  337. //
  338. // QTUtils_ShowControllerBar
  339. // Show the controller bar provided by the movie controller.
  340. //
  341. //////////
  342.  
  343. void QTUtils_ShowControllerBar (MovieController theMC) 
  344. {
  345.     MCSetVisible(theMC, true);
  346. }
  347.  
  348.  
  349. //////////
  350. //
  351. // QTUtils_ToggleControllerBar
  352. // Toggle the state of the controller bar provided by the movie controller.
  353. //
  354. //////////
  355.  
  356. void QTUtils_ToggleControllerBar (MovieController theMC) 
  357. {
  358.     if (QTUtils_IsControllerBarVisible(theMC))
  359.         QTUtils_HideControllerBar(theMC);
  360.     else
  361.         QTUtils_ShowControllerBar(theMC);
  362. }
  363.  
  364.  
  365. //////////
  366. //
  367. // QTUtils_HideControllerButton
  368. // Hide the specified button in the controller bar.
  369. //
  370. // Some explanation is probably useful here: the first thing to understand is that every VR movie has 
  371. // TWO sets of movie controller flags: (1) a set of "control flags" and (2) a set of "explicit flags".
  372. //
  373. // The control flags work as documented in IM: QuickTime Components (pp. 2-20f) and in VRPWQTVR2.0 (pp. 2-23f):
  374. // if a bit in the set of control flags is set (that is, equal to 1), then the associated action or property is
  375. // enabled. For instance, bit 17 (mcFlagQTVRSuppressZoomBtns) means to suppress the zoom buttons. So, if that
  376. // bit is set in a VR movie's control flags, the zoom buttons are NOT displayed. If that bit is clear, the zoom
  377. // buttons are displayed.
  378. //
  379. // However, the QuickTime VR movie controller sometimes suppresses buttons even when those buttons 
  380. // have not been explicitly suppressed in the control flags. For example, if a particular VR movie does not
  381. // contain a sound track, then the movie controller automatically suppresses the speaker/volume button. Likewise,
  382. // if a movie does contain a sound track, then the speaker/volume button is automatically displayed, again without
  383. // regard to the actual value of bit 17 in the control flags.
  384. //
  385. // This might not be what you'd like to happen. For instance, if your application is playing a sound that it
  386. // loaded from a sound resource, you might want the user to be able to adjust the sound's volume using the volume
  387. // control. To do that, you need a way to *force* the speaker/volume button to appear. For this reason, the
  388. // explicit flags were introduced.
  389. //
  390. // The explicit flags indicate which bits in the control flags are to be used explicitly (that is, taken at
  391. // face value). If a certain bit is set in a movie's explicit flags, then the corresponding bit in the control
  392. // flags is interpreted as the desired setting for the feature (and the movie controller will not attempt to
  393. // do anything "clever"). In other words, if bit 17 is set in a movie's explicit flags and bit 17 is clear in
  394. // that movie's control flags, then the zoom buttons are displayed. Similarly, if bit 2 is set in a movie's 
  395. // explicit flags and bit 2 is clear in that movie's control flags, then the speaker/volume button is displayed,
  396. // whether or not the movie contains a sound track.
  397. //
  398. // The final thing to understand: to get or set a bit in a movie's explicit flags, you must set the flag 
  399. // mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags or mcActionSetFlags. To get or set a bit in a 
  400. // movie's control flags, you must clear the flag mcFlagQTVRExplicitFlagSet in your call to mcActionGetFlags 
  401. // or mcActionSetFlags. Note that when you use the defined constants to set values in the explicit flags, the 
  402. // constant names might be confusing. For instance, setting the bit mcFlagSuppressSpeakerButton in a movie's
  403. // explicit flags doesn't cause the speaker to be suppressed; it just means: "use the actual value of the
  404. // mcFlagSuppressSpeakerButton bit in the control flags".
  405. //
  406. // Whew! Any questions? Okay, then now you'll understand how to hide or show a button in the controller bar:
  407. // set the appropriate explicit flag to 1 and set the corresponding control flag to the desired value. And
  408. // you'll understand how to let the movie controller do its "clever" work: clear the appropriate explicit flag.
  409. //
  410. //////////
  411.  
  412. void QTUtils_HideControllerButton (MovieController theMC, long theButton) 
  413. {
  414.     long    myControllerFlags;
  415.     
  416.     // get the current explicit flags and set the explicit flag for the specified button
  417.     myControllerFlags = mcFlagQTVRExplicitFlagSet;
  418.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  419.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  420.     
  421.     // get the current control flags and set the suppress flag for the specified button
  422.     myControllerFlags = 0;
  423.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  424.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  425. }
  426.  
  427.  
  428. //////////
  429. //
  430. // QTUtils_ShowControllerButton
  431. // Show the specified button in the controller bar.
  432. //
  433. //////////
  434.  
  435. void QTUtils_ShowControllerButton (MovieController theMC, long theButton) 
  436. {
  437.     long    myControllerFlags;
  438.     
  439.     // get the current explicit flags and set the explicit flag for the specified button
  440.     myControllerFlags = mcFlagQTVRExplicitFlagSet;
  441.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  442.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) | mcFlagQTVRExplicitFlagSet));
  443.     
  444.     // get the current control flags and clear the suppress flag for the specified button
  445.     myControllerFlags = 0;
  446.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  447.     MCDoAction(theMC, mcActionSetFlags, (void *)(myControllerFlags & ~theButton & ~mcFlagQTVRExplicitFlagSet));
  448. }
  449.  
  450.  
  451. //////////
  452. //
  453. // QTUtils_ToggleControllerButton
  454. // Toggle the state of the specified button in the controller bar.
  455. //
  456. //////////
  457.  
  458. void QTUtils_ToggleControllerButton (MovieController theMC, long theButton) 
  459. {
  460.     long    myControllerFlags;
  461.     
  462.     // get the current control flags and toggle the suppress flag for the specified button
  463.     myControllerFlags = 0;
  464.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  465.     
  466.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  467.         QTUtils_ShowControllerButton(theMC, theButton);
  468.     else
  469.         QTUtils_HideControllerButton(theMC, theButton);
  470. }
  471.  
  472.  
  473. //////////
  474. //
  475. // QTUtils_ResetControllerButton
  476. // Remove any explicit setting of the specified button in the controller bar.
  477. // (This allows the QuickTime VR movie controller to be as clever as it knows how to be.)
  478. //
  479. //////////
  480.  
  481. void QTUtils_ResetControllerButton (MovieController theMC, long theButton) 
  482. {
  483.     long    myControllerFlags = mcFlagQTVRExplicitFlagSet;
  484.     
  485.     // get the current explicit flags and clear the explicit flag for the specified button
  486.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  487.     MCDoAction(theMC, mcActionSetFlags, (void *)((myControllerFlags | theButton) & ~mcFlagQTVRExplicitFlagSet));
  488. }
  489.  
  490.  
  491. //////////
  492. //
  493. // QTUtils_IsControllerButtonVisible
  494. // Is the specified button in the controller bar currently visible?
  495. //
  496. //////////
  497.  
  498. Boolean QTUtils_IsControllerButtonVisible (MovieController theMC, long theButton) 
  499. {
  500.     long        myControllerFlags;
  501.  
  502.     // get the current control flags
  503.     myControllerFlags = 0;
  504.     MCDoAction(theMC, mcActionGetFlags, &myControllerFlags);
  505.  
  506.     // the speaker button requires some additional logic, because the QTVR movie controller treats it special;
  507.     // be advised that that controller's special behavior could change in the future,
  508.     // so you might need to tweak this code
  509.     if (theButton == mcFlagSuppressSpeakerButton) {
  510.         long    myExplicitFlags;
  511.         
  512.         // get the current explicit flags
  513.         myExplicitFlags = mcFlagQTVRExplicitFlagSet;
  514.         MCDoAction(theMC, mcActionGetFlags, &myExplicitFlags);
  515.     
  516.         // the speaker button is not showing if the movie has no sound track and the explicit flag is not set
  517.         if (!QTUtils_MovieHasSoundTrack(MCGetMovie(theMC)) && !(myExplicitFlags & theButton))
  518.             return(false);
  519.     }
  520.     
  521.     // examine the suppress flag for the specified button
  522.     if (myControllerFlags & theButton)                // if the button is currently suppressed...
  523.         return(false);
  524.     else
  525.         return(true);
  526. }
  527.  
  528.  
  529. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  530. //
  531. // Media utilities.
  532. //
  533. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  534.  
  535. //////////
  536. //
  537. // QTUtils_IsMediaTypeInMovie
  538. // Determine whether a specific media type is in a movie.
  539. // 
  540. //////////
  541.  
  542. Boolean QTUtils_IsMediaTypeInMovie (Movie theMovie, OSType theMediaType)
  543. {
  544.     return(GetMovieIndTrackType(theMovie, 1, theMediaType, movieTrackMediaType | movieTrackEnabledOnly) != NULL);
  545. }
  546.  
  547.  
  548. //////////
  549. //
  550. // QTUtils_MovieHasTimeCodeTrack
  551. // Determine whether a movie contains a timecode track.
  552. // 
  553. //////////
  554.  
  555. Boolean QTUtils_MovieHasTimeCodeTrack (Movie theMovie)
  556. {
  557.     return(GetMovieIndTrackType(theMovie, 1, TimeCodeMediaType, movieTrackMediaType) != NULL);
  558. }
  559.  
  560.  
  561. //////////
  562. //
  563. // QTUtils_MovieHasSoundTrack
  564. // Determine whether a movie contains a sound track.
  565. // 
  566. //////////
  567.  
  568. Boolean QTUtils_MovieHasSoundTrack (Movie theMovie)
  569. {
  570.     return(GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly) != NULL);
  571. }
  572.  
  573.  
  574. //////////
  575. //
  576. // QTUtils_GetSoundMediaHandler
  577. // Return the sound media handler for a movie.
  578. // 
  579. //////////
  580.  
  581. MediaHandler QTUtils_GetSoundMediaHandler (Movie theMovie)
  582. {
  583.     Track        myTrack;
  584.     Media        myMedia;
  585.  
  586.     myTrack = GetMovieIndTrackType(theMovie, 1, AudioMediaCharacteristic, movieTrackCharacteristic | movieTrackEnabledOnly);
  587.     if (myTrack != NULL) {
  588.         myMedia = GetTrackMedia(myTrack);
  589.         return(GetMediaHandler(myMedia));
  590.     } 
  591.         
  592.     return(NULL);
  593. }
  594.  
  595.  
  596. //////////
  597. //
  598. // QTUtils_UpdateMovieVolumeSetting
  599. // Update the preferred volume setting of the specified movie.
  600. // 
  601. //////////
  602.  
  603. OSErr QTUtils_UpdateMovieVolumeSetting (Movie theMovie)
  604. {
  605.     short            myPrefVolume;
  606.     short            myCurrVolume;
  607.     OSErr            myErr = noErr;
  608.     
  609.     myPrefVolume = GetMoviePreferredVolume(theMovie);
  610.     myCurrVolume = GetMovieVolume(theMovie);
  611.     myCurrVolume = abs(myCurrVolume);
  612.     
  613.     if (myPrefVolume != myCurrVolume) {
  614.         SetMoviePreferredVolume(theMovie, myCurrVolume);
  615.         myErr = GetMoviesError();
  616.     }
  617.     
  618.     return(myErr);
  619. }
  620.  
  621.  
  622. //////////
  623. //
  624. // QTUtils_PrintMoviePICT
  625. // Print the existing movie frame pict.
  626. // 
  627. // Note that in a real application we should put the PrStlDialog code into the Print Setup… menu
  628. // function. The reason it's inside this function is that we use this code for quick testing of printing.
  629. //
  630. //////////
  631.  
  632. OSErr QTUtils_PrintMoviePICT (Movie theMovie, short x, short y, long PICTUsed)
  633. {
  634.     PicHandle         myPictHandle = NULL;
  635.     THPrint            myTHPrint = NULL;
  636.     GrafPtr             mySavedPort;
  637.     TPPrPort        myPrintPort;
  638.     Boolean         myResult;
  639.     Boolean            isPrinting = false;
  640.     Rect            myPictRect;
  641.     OSErr            myErr = noErr;
  642.     
  643.     if (theMovie == NULL)
  644.         return(invalidMovie);
  645.     
  646.     GetPort(&mySavedPort);
  647.  
  648.     // get the PICT to be printed, either the poster pict or the current frame pict.
  649.     switch (PICTUsed) {
  650.         case kPrintFrame:
  651.             myPictHandle = GetMoviePict(theMovie, GetMovieTime(theMovie, 0L));
  652.             break;
  653.             
  654.         case kPrintPoster:
  655.             myPictHandle = GetMoviePosterPict(theMovie); 
  656.             break;
  657.  
  658.         default:
  659.             goto Closure;
  660.     }
  661.  
  662.     if (myPictHandle == NULL)
  663.         goto Closure;
  664.  
  665. #if TARGET_RT_LITTLE_ENDIAN
  666.     // change the fields of the Picture structure,
  667.     // if the target runtime environment uses little-endian format for integers
  668.     (**myPictHandle).picSize = EndianS16_BtoL((**myPictHandle).picSize);
  669.     
  670.     (**myPictHandle).picFrame.top = EndianS16_BtoL((**myPictHandle).picFrame.top);
  671.     (**myPictHandle).picFrame.left = EndianS16_BtoL((**myPictHandle).picFrame.left);
  672.     (**myPictHandle).picFrame.bottom = EndianS16_BtoL((**myPictHandle).picFrame.bottom);
  673.     (**myPictHandle).picFrame.right = EndianS16_BtoL((**myPictHandle).picFrame.right);
  674. #endif        
  675.  
  676.     // get the Print record
  677.     myTHPrint = (THPrint)NewHandleClear(sizeof(TPrint));
  678.     if (myTHPrint == NULL)
  679.         goto Closure;
  680.  
  681.     PrOpen();
  682.     isPrinting = true;
  683.     myErr = PrError();
  684.     if (myErr != noErr)
  685.         goto Closure;
  686.  
  687.     PrintDefault(myTHPrint);
  688.  
  689.     // move this to Print Setup… if you want to make this look really cool
  690.     myResult = PrStlDialog(myTHPrint);
  691.     if (!myResult)
  692.         goto Closure;
  693.     
  694.     myResult = PrJobDialog(myTHPrint);
  695.     if (!myResult)
  696.         goto Closure;
  697.     
  698.     myPrintPort = PrOpenDoc(myTHPrint, NULL, NULL);
  699.     PrOpenPage(myPrintPort, NULL);
  700.     myErr = PrError();
  701.     if (myErr != noErr)
  702.         goto Closure;
  703.     
  704.     // print at x,y position
  705.     myPictRect = (*myPictHandle)->picFrame;
  706.     MacOffsetRect(&myPictRect, (short)(x - myPictRect.left),  (short)(y - myPictRect.top));
  707.     
  708.     DrawPicture(myPictHandle, &myPictRect);
  709.  
  710.     // if you want to do additional drawing, do it here.
  711.     
  712.     PrClosePage(myPrintPort);
  713.     PrCloseDoc(myPrintPort);
  714.     myErr = PrError();
  715.     if (myErr != noErr)
  716.         goto Closure;
  717.     
  718.     if ((*myTHPrint)->prJob.bJDocLoop == bSpoolLoop)
  719.         PrPicFile(myTHPrint, NULL, NULL, NULL, NULL);
  720.     
  721.     // our closure handling
  722. Closure:
  723.     MacSetPort(mySavedPort);
  724.     
  725.     if (isPrinting)
  726.         PrClose();
  727.     if (myPictHandle)
  728.         KillPicture(myPictHandle);
  729.     if (myTHPrint)
  730.         DisposeHandle((Handle)myTHPrint);
  731.  
  732.     return(myErr);
  733. }
  734.  
  735.  
  736. //////////
  737. //
  738. // QTUtils_SelectAllMovie
  739. // Select the entire movie associated with the specified movie controller.
  740. // 
  741. //////////
  742.  
  743. OSErr QTUtils_SelectAllMovie (MovieController theMC)
  744. {
  745.     TimeRecord            myTimeRecord;
  746.     Movie                 myMovie = NULL;
  747.     ComponentResult        myErr = noErr;
  748.     
  749.     if (theMC == NULL)
  750.         return(paramErr);
  751.     
  752.     myMovie = MCGetMovie(theMC);
  753.     if (myMovie == NULL)
  754.         return(paramErr);
  755.     
  756.     myTimeRecord.value.hi = 0;
  757.     myTimeRecord.value.lo = 0;
  758.     myTimeRecord.base = 0;
  759.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  760.     myErr = MCDoAction(theMC, mcActionSetSelectionBegin, &myTimeRecord);
  761.     if (myErr != noErr)
  762.         return((OSErr)myErr);
  763.     
  764.     myTimeRecord.value.hi = 0;
  765.     myTimeRecord.value.lo = GetMovieDuration(myMovie);    
  766.     myTimeRecord.base = 0;
  767.     myTimeRecord.scale = GetMovieTimeScale(myMovie);    
  768.     myErr = MCDoAction(theMC, mcActionSetSelectionDuration, &myTimeRecord);
  769.     
  770.     return((OSErr)myErr);
  771. }
  772.  
  773.  
  774. //////////
  775. //
  776. // QTUtils_MakeSampleDescription
  777. // Return a new image description with default and specified values.
  778. // 
  779. //////////
  780.  
  781. ImageDescriptionHandle QTUtils_MakeSampleDescription (long theEffectType, short theWidth, short theHeight)
  782. {
  783.     ImageDescriptionHandle        mySampleDesc = NULL;
  784.     OSErr                        myErr = noErr;
  785.  
  786.     // create a new sample description
  787.     mySampleDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  788.     if (mySampleDesc == NULL)
  789.         return(NULL);
  790.     
  791.     // fill in the fields of the sample description
  792.     (**mySampleDesc).idSize = sizeof(ImageDescription);
  793.     (**mySampleDesc).cType = theEffectType;
  794.     (**mySampleDesc).vendor = kAppleManufacturer;
  795.     (**mySampleDesc).temporalQuality = codecNormalQuality;
  796.     (**mySampleDesc).spatialQuality = codecNormalQuality;
  797.     (**mySampleDesc).width = theWidth;
  798.     (**mySampleDesc).height = theHeight;
  799.     (**mySampleDesc).hRes = 72L << 16;
  800.     (**mySampleDesc).vRes = 72L << 16;
  801.     (**mySampleDesc).dataSize = 0L;
  802.     (**mySampleDesc).frameCount = 1;
  803.     (**mySampleDesc).depth = 24;
  804.     (**mySampleDesc).clutID = -1;
  805.     
  806.     return(mySampleDesc);
  807. }
  808.  
  809.  
  810. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  811. //
  812. // User data utilities.
  813. //
  814. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  815.  
  816. #if CONTENT_RATING_AVAIL
  817. //////////
  818. //
  819. // QTUtils_GetContentRatingFromMovie
  820. // Get the content rating from a movie; return an error if it has none. In any case, return a meaningful
  821. // content rating.
  822. //
  823. //////////
  824.  
  825. OSErr QTUtils_GetContentRatingFromMovie (Movie theMovie, UInt16 *theRating, UInt32 *theReasons)
  826. {
  827.     UserData                    myUserData;
  828.     QTAltContentRatingRecord    myContentRec;
  829.     OSErr                        myErr = paramErr;
  830.  
  831.     *theRating = kQTContentTVYRating;
  832.     *theReasons = 0L;
  833.  
  834.     // make sure we've got a movie
  835.     if (theMovie == NULL)
  836.         return(myErr);
  837.         
  838.     // get the movie's user data list
  839.     myUserData = GetMovieUserData(theMovie);
  840.     if (myUserData != NULL) {
  841.         myErr = GetUserDataItem(myUserData, &myContentRec, sizeof(myContentRec), FOUR_CHAR_CODE('crat'), 0);
  842.         if (myErr == noErr) {
  843.             *theRating = EndianU16_BtoN(myContentRec.ratings);
  844.             *theReasons = EndianU32_BtoN(myContentRec.contentType);
  845.         }
  846.     }
  847.  
  848.     return(myErr);
  849. }
  850.  
  851.  
  852. //////////
  853. //
  854. // QTUtils_AddContentRatingToMovie
  855. // Add a content rating to a movie.
  856. //
  857. // A content rating is stored as a user data item that indicates both the general rating
  858. // (for example, TV-MA [mature audiences only]) and any additional information about the
  859. // content (for example, coarse language). Let's call this additional information the
  860. // "reasons" for the rating. Both the rating and the reasons are specified using constants
  861. // in the file MoviesFormat.h.
  862. //
  863. // This function adds the specified content rating to the movie's user data;
  864. // the updated user data is written to the movie file when the movie is next updated
  865. // (by calling UpdateMovieResource).
  866. // 
  867. //////////
  868.  
  869. OSErr QTUtils_AddContentRatingToMovie (Movie theMovie, UInt16 theRating, UInt32 theReasons)
  870. {
  871.     UserData                    myUserData;
  872.     QTAltContentRatingRecord    myContentRec;
  873.     OSErr                        myErr = noErr;
  874.  
  875.     // get the movie's user data list
  876.     myUserData = GetMovieUserData(theMovie);
  877.     if (myUserData == NULL)
  878.         return(paramErr);
  879.     
  880.     myContentRec.flags = 0;
  881.     myContentRec.contentType = EndianU32_NtoB(theReasons);
  882.     myContentRec.ratings = EndianU16_NtoB(theRating);
  883.     
  884.     // for simplicity, we assume that we want only one content rating in the movie;
  885.     // as a result, we won't worry about overwriting any existing item of that type
  886.  
  887.     // add the data to the movie's user data
  888.     myErr = SetUserDataItem(myUserData, &myContentRec, sizeof(myContentRec), FOUR_CHAR_CODE('crat'), 0);
  889.  
  890.     return(myErr);
  891. }
  892. #endif    // #if CONTENT_RATING_AVAIL
  893.  
  894.  
  895. //////////
  896. //
  897. // QTUtils_AddUserDataTextToMovie
  898. // Add a user data item, of the specified type, containing the specified text to a movie.
  899. //
  900. // This function adds the specified text to the movie's user data;
  901. // the updated user data is written to the movie file when the movie is next updated
  902. // (by calling UpdateMovieResource).
  903. // 
  904. //////////
  905.  
  906. OSErr QTUtils_AddUserDataTextToMovie (Movie theMovie, char *theText, OSType theType)
  907. {
  908.     UserData                    myUserData;
  909.     Handle                        myHandle = NULL;
  910.     short                        myIndex = 0;
  911.     long                        myLength = strlen(theText);
  912.     OSErr                        myErr = noErr;
  913.  
  914.     // get the movie's user data list
  915.     myUserData = GetMovieUserData(theMovie);
  916.     if (myUserData == NULL)
  917.         return(paramErr);
  918.     
  919.     // copy the specified text into a new handle
  920.     myHandle = NewHandleClear(myLength);
  921.     if (myHandle == NULL)
  922.         return(MemError());
  923.  
  924.     BlockMoveData(theText, *myHandle, myLength);
  925.  
  926.     // for simplicity, we assume that we want only one user data item of the specified type in the movie;
  927.     // as a result, we won't worry about overwriting any existing item of that type....
  928.     //
  929.     // if you need multiple user data items of a given type (for example, a copyright notice
  930.     // in several different languages), you would need to modify this code; this is left as an exercise
  931.     // for the reader....
  932.  
  933.     // add the data to the movie's user data
  934.     myErr = AddUserDataText(myUserData, myHandle, theType, myIndex + 1, smSystemScript);
  935.  
  936.     // clean up
  937.     DisposeHandle(myHandle);
  938.     return(myErr);
  939. }
  940.  
  941.  
  942. //////////
  943. //
  944. // QTUtils_AddCopyrightToMovie
  945. // Add a user data item containing the specified copyright text to a movie.
  946. //
  947. //////////
  948.  
  949. OSErr QTUtils_AddCopyrightToMovie (Movie theMovie, char *theText)
  950. {
  951.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextCopyright));
  952. }
  953.  
  954.  
  955. //////////
  956. //
  957. // QTUtils_AddMovieNameToMovie
  958. // Add a user data item containing the specified name to a movie.
  959. //
  960. //////////
  961.  
  962. OSErr QTUtils_AddMovieNameToMovie (Movie theMovie, char *theText)
  963. {
  964.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextFullName));
  965. }
  966.  
  967.  
  968. //////////
  969. //
  970. // QTUtils_AddMovieInfoToMovie
  971. // Add a user data item containing the specified information to a movie.
  972. //
  973. //////////
  974.  
  975. OSErr QTUtils_AddMovieInfoToMovie (Movie theMovie, char *theText)
  976. {
  977.     return(QTUtils_AddUserDataTextToMovie(theMovie, theText, kUserDataTextInformation));
  978. }
  979.  
  980.  
  981. //////////
  982. //
  983. // QTUtils_GetMovieFileLoopingInfo
  984. // Get the looping state of a movie file.
  985. //
  986. // A movie file can have information about its looping state in a user data item of type 'LOOP'.
  987. // If the movie doesn't contain an item of this type, then we'll assume that it isn't looping.
  988. // If it does contain an item of this type, then the item data (a long integer) is 0 for normal
  989. // looping and 1 for palindrome looping. Accordingly, this function returns the following values
  990. // in the theLoopInfo parameter:
  991. //
  992. //        0 == normal looping
  993. //        1 == palindrome looping
  994. //        2 == no looping
  995. //
  996. //////////
  997.  
  998. OSErr QTUtils_GetMovieFileLoopingInfo (Movie theMovie, long *theLoopInfo)
  999. {
  1000.     UserData        myUserData;
  1001.     long            myInfo = kNoLooping;
  1002.     OSErr            myErr = paramErr;
  1003.  
  1004.     // make sure we've got a movie
  1005.     if (theMovie == NULL)
  1006.         goto bail;
  1007.         
  1008.     // get the movie's user data list
  1009.     myUserData = GetMovieUserData(theMovie);
  1010.     if (myUserData != NULL)
  1011.         myErr = GetUserDataItem(myUserData, &myInfo, sizeof(myInfo), FOUR_CHAR_CODE('LOOP'), 0);
  1012.  
  1013. bail:
  1014.     *theLoopInfo = myInfo;
  1015.  
  1016.     return(myErr);
  1017. }
  1018.  
  1019.  
  1020. //////////
  1021. //
  1022. // QTUtils_SetMovieFileLoopingInfo
  1023. // Set the looping state for a movie file.
  1024. //
  1025. //////////
  1026.  
  1027. OSErr QTUtils_SetMovieFileLoopingInfo (Movie theMovie, long theLoopInfo)
  1028. {
  1029.     UserData        myUserData;
  1030.     short            myCount = 0;
  1031.     OSErr            myErr = paramErr;
  1032.  
  1033.     // get the movie's user data
  1034.     myUserData = GetMovieUserData(theMovie);
  1035.     if (myUserData == NULL)
  1036.         goto bail;
  1037.  
  1038.     // we want to end up with at most one user data item of type 'LOOP',
  1039.     // so let's remove any existing ones
  1040.     myCount = CountUserDataType(myUserData, FOUR_CHAR_CODE('LOOP'));
  1041.     while (myCount--)
  1042.         RemoveUserData(myUserData, FOUR_CHAR_CODE('LOOP'), 1);
  1043.  
  1044.     switch (theLoopInfo) {
  1045.         case kNormalLooping:
  1046.         case kPalindromeLooping:
  1047.             myErr = SetUserDataItem(myUserData, &theLoopInfo, sizeof(long), FOUR_CHAR_CODE('LOOP'), 0);
  1048.             break;
  1049.  
  1050.         case kNoLooping:
  1051.         default:
  1052.             myErr = noErr;
  1053.             break;
  1054.     }
  1055.  
  1056. bail:
  1057.     return(myErr);
  1058. }
  1059.  
  1060.  
  1061. //////////
  1062. //
  1063. // QTUtils_SetLoopingStateFromFile
  1064. // Set the looping state for a movie based on the looping information in the movie file.
  1065. //
  1066. //////////
  1067.  
  1068. OSErr QTUtils_SetLoopingStateFromFile (Movie theMovie, MovieController theMC)
  1069. {
  1070.     long             myLoopInfo;
  1071.     OSErr            myErr = noErr;
  1072.  
  1073.     myErr = QTUtils_GetMovieFileLoopingInfo(theMovie, &myLoopInfo);
  1074.     switch (myLoopInfo) {
  1075.  
  1076.         case kNormalLooping:
  1077.             MCDoAction(theMC, mcActionSetLooping, (void *)true);
  1078.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)false);
  1079.             break;
  1080.  
  1081.         case kPalindromeLooping:
  1082.             MCDoAction(theMC, mcActionSetLooping, (void *)true);
  1083.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)true);
  1084.             break;
  1085.  
  1086.         case kNoLooping:
  1087.         default:
  1088.             MCDoAction(theMC, mcActionSetLooping, (void *)false);
  1089.             MCDoAction(theMC, mcActionSetLoopIsPalindrome, (void *)false);
  1090.             break;
  1091.     }
  1092.  
  1093.     return(myErr);
  1094. }
  1095.  
  1096.  
  1097. //////////
  1098. //
  1099. // QTUtils_MakeMovieLoop
  1100. // Set the specified movie to loop.
  1101. //
  1102. // Based on the function MakeMovieLoop by Kevin Marks.
  1103. //
  1104. //////////
  1105.  
  1106. OSErr QTUtils_MakeMovieLoop (Movie theMovie, Boolean isPalindrome)
  1107. {
  1108.     TimeBase        myTimeBase = NULL;
  1109.     long             myFlags = 0L;
  1110.     OSErr            myErr = paramErr;
  1111.  
  1112.     // make sure we've got a movie
  1113.     if (theMovie == NULL)
  1114.         goto bail;
  1115.     
  1116.     myErr = noErr;
  1117.         
  1118.     // set the movie's play hints to enhance looping performance
  1119.     SetMoviePlayHints(theMovie, hintsLoop, hintsLoop);
  1120.     
  1121.     // set the looping flag of the movie's time base
  1122.     myTimeBase = GetMovieTimeBase(theMovie);
  1123.     myFlags = GetTimeBaseFlags(myTimeBase);
  1124.     myFlags |= loopTimeBase;
  1125.     
  1126.     // set or clear the palindrome flag, depending on the specified setting
  1127.     if (isPalindrome)
  1128.         myFlags |= palindromeLoopTimeBase;
  1129.     else
  1130.         myFlags &= ~palindromeLoopTimeBase;
  1131.         
  1132.     SetTimeBaseFlags(myTimeBase, myFlags);
  1133.  
  1134. bail:
  1135.     return(myErr);
  1136. }
  1137.  
  1138.  
  1139. //////////
  1140. //
  1141. // QTUtils_GetTrackName
  1142. // Get the name of the specified movie track.
  1143. //
  1144. // This routine is modelled on the one contained in Dispatch 2 from the Ice Floe;
  1145. // I've modified it to return a C string instead of a Pascal string.
  1146. //
  1147. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1148. //
  1149. //////////
  1150.  
  1151. char *QTUtils_GetTrackName (Track theTrack)
  1152. {
  1153.     UserData            myUserData;
  1154.     char                *myString = NULL;
  1155.      OSErr                myErr = noErr;
  1156.  
  1157.     // make sure we've got a track
  1158.     if (theTrack == NULL)
  1159.         return(NULL);
  1160.         
  1161.     // a track's name (if it has one) is stored in the track's user data
  1162.     myUserData = GetTrackUserData(theTrack);
  1163.     if (myUserData != NULL) {
  1164.         Handle            myHandle = NewHandle(0);
  1165.  
  1166.         // get the user data item of type kUserDataName;
  1167.         // the handle we pass to GetUserData is resized to contain the track name
  1168.         myErr = GetUserData(myUserData, myHandle, kUserDataName, 1);
  1169.         if (myErr == noErr) {
  1170.             long        myLength = GetHandleSize(myHandle);
  1171.  
  1172.             if (myLength > 0) {
  1173.                 myString = malloc(myLength + 1);
  1174.                 if (myString != NULL) {
  1175.                     memcpy(myString, *myHandle, myLength);
  1176.                     myString[myLength] = '\0';
  1177.                 }
  1178.             }            
  1179.         }    
  1180.  
  1181.         DisposeHandle(myHandle);
  1182.     }
  1183.  
  1184.     return(myString);
  1185. }
  1186.  
  1187.  
  1188. //////////
  1189. //
  1190. // QTUtils_SetTrackName
  1191. // Set the name of the specified movie track.
  1192. //
  1193. // This function adds the specified text to the track's user data;
  1194. // the updated user data is written to the movie file when the movie is next updated
  1195. // (by calling UpdateMovieResource).
  1196. //
  1197. //////////
  1198.  
  1199. OSErr QTUtils_SetTrackName (Track theTrack, char *theText)
  1200. {
  1201.     UserData            myUserData;
  1202.     OSErr                myErr = noErr;
  1203.  
  1204.     // make sure we've got a track and a name
  1205.     if ((theTrack == NULL) || (theText == NULL))
  1206.         return(paramErr);
  1207.         
  1208.     // get the track's user data list
  1209.     myUserData = GetTrackUserData(theTrack);
  1210.     if (myUserData == NULL)
  1211.         return(paramErr);
  1212.     
  1213.     // remove any existing track name
  1214.     while (RemoveUserData(myUserData, kUserDataName, 1) == noErr)
  1215.         ;
  1216.  
  1217.     myErr = SetUserDataItem(myUserData, theText, strlen(theText), kUserDataName, 0);
  1218.  
  1219.     return(myErr);
  1220. }
  1221.  
  1222.  
  1223. //////////
  1224. //
  1225. // QTUtils_MakeTrackNameByType
  1226. // Create a (unique) name for the specified track, based on the track's type.
  1227. //
  1228. // Given a movie track, this routine constructs a name for that track based on
  1229. // the media type of that track. For instance, if the track is a sound track,
  1230. // this routine returns the name "Sound". However, if there is more than one
  1231. // track of that media type, then this routine numbers the track names. So, if
  1232. // there are two sound tracks, this routine names them "Sound 1" and "Sound 2".
  1233. //
  1234. // This routine is modelled on the one contained in Dispatch 2 from the Ice Floe;
  1235. // I've modified it to return a C string instead of a Pascal string.
  1236. //
  1237. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1238. //
  1239. //////////
  1240.  
  1241. char *QTUtils_MakeTrackNameByType (Track theTrack)
  1242. {
  1243.     Media                myMedia;
  1244.     char                *myString = NULL;
  1245.      OSErr                myErr = noErr;
  1246.  
  1247.     // make sure we've got a track
  1248.     if (theTrack == NULL)
  1249.         return(NULL);
  1250.     
  1251.     myMedia = GetTrackMedia(theTrack);
  1252.     if (myMedia != NULL) {
  1253.         MediaHandler    myMediaHandler = GetMediaHandler(myMedia);
  1254.         OSType            myMediaType;
  1255.         Str255            myName;
  1256.  
  1257.         // get the media type of the track
  1258.         GetMediaHandlerDescription(myMedia, &myMediaType, NULL, NULL);
  1259.         
  1260.         // get the text of the media type
  1261.         myErr = MediaGetName(myMediaHandler, myName, 0, NULL);
  1262.         if (myErr == noErr) {
  1263.             
  1264.             // determine whether there's more than one track with this media type
  1265.             if (GetMovieIndTrackType(GetTrackMovie(theTrack), 2, myMediaType, movieTrackMediaType) != NULL) {
  1266.  
  1267.                 // add an index number to the track type string we constructed above
  1268.                 long    myIndex = 1;
  1269.                 Str255    myNumString;
  1270.  
  1271.                 while (GetMovieIndTrackType(GetTrackMovie(theTrack), myIndex, myMediaType, movieTrackMediaType) != theTrack)
  1272.                    myIndex++;
  1273.  
  1274.                 NumToString(myIndex, myNumString);
  1275.                 myName[++myName[0]] = ' ';
  1276.                 BlockMoveData(&myNumString[1], &myName[myName[0] + 1], myNumString[0]);
  1277.                 myName[0] += myNumString[0];
  1278.             }
  1279.  
  1280.             // now copy the string data from the Pascal string to a C string
  1281.             if (myName[0] > 0) {
  1282.                 myString = malloc(myName[0] + 1);
  1283.                 if (myString != NULL) {
  1284.                     memcpy(myString, &myName[1], myName[0]);
  1285.                     myString[myName[0]] = '\0';
  1286.                 }
  1287.             }            
  1288.         }
  1289.     }
  1290.  
  1291.     return(myString);
  1292. }
  1293.  
  1294.  
  1295. //////////
  1296. //
  1297. // QTUtils_IsImageFile
  1298. // Is the specified file an image file?
  1299. //
  1300. //////////
  1301.  
  1302. Boolean QTUtils_IsImageFile (FSSpec *theFSSpec)
  1303. {    
  1304.     Boolean                        isImageFile = false;
  1305.     GraphicsImportComponent        myImporter = NULL;
  1306.  
  1307.     GetGraphicsImporterForFile(theFSSpec, &myImporter);
  1308.     if (myImporter != NULL) {
  1309.         // this file is a still image
  1310.         isImageFile = true;
  1311.         CloseComponent(myImporter);
  1312.     }
  1313.  
  1314.     return(isImageFile);
  1315. }
  1316.  
  1317.  
  1318. //////////
  1319. //
  1320. // QTUtils_IsMovieFile
  1321. // Is the specified file a file that can be opened by QuickTime as a movie?
  1322. //
  1323. // This apparently isn't working correctly: GMIFDR always returns -2003 (cantFindHandler)
  1324. //
  1325. //////////
  1326.  
  1327. Boolean QTUtils_IsMovieFile (FSSpec *theFSSpec)
  1328. {    
  1329.     Boolean                        isMovieFile = false;
  1330.     AliasHandle                    myAlias = NULL;
  1331.     Component                    myImporter = NULL;
  1332.     OSErr                        myErr = noErr;
  1333.  
  1334.     NewAliasMinimal(theFSSpec, &myAlias);
  1335.     GetMovieImporterForDataRef(rAliasType, (Handle)myAlias, kGetMovieImporterDontConsiderGraphicsImporters, &myImporter);
  1336.  
  1337.     DisposeHandle((Handle)myAlias);
  1338.     if (myImporter != NULL)        // this file is a movie file
  1339.         isMovieFile = true;
  1340.  
  1341.     return(isMovieFile);
  1342. }
  1343.  
  1344.  
  1345. //////////
  1346. //
  1347. // QTUtils_ConvertFloatToBigEndian
  1348. // Convert the specified floating-point number to big-endian format.
  1349. //
  1350. //////////
  1351.  
  1352. void QTUtils_ConvertFloatToBigEndian (float *theFloat)
  1353. {
  1354.     unsigned long        *myLongPtr;
  1355.     
  1356.     myLongPtr = (unsigned long *)theFloat;
  1357.     *myLongPtr = EndianU32_NtoB(*myLongPtr);
  1358. }
  1359.  
  1360.  
  1361. //////////
  1362. //
  1363. // QTUtils_ConvertCToPascalString
  1364. // Convert a C string into a Pascal string.
  1365. //
  1366. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1367. //
  1368. //////////
  1369.  
  1370. StringPtr QTUtils_ConvertCToPascalString (char *theString)
  1371. {
  1372.     StringPtr    myString = malloc(strlen(theString) + 1);
  1373.     short        myIndex = 0;
  1374.  
  1375.     while (theString[myIndex] != '\0') {
  1376.         myString[myIndex + 1] = theString[myIndex];
  1377.         myIndex++;
  1378.     }
  1379.     
  1380.     myString[0] = (unsigned char)myIndex;
  1381.     
  1382.     return(myString);
  1383. }
  1384.  
  1385.  
  1386. //////////
  1387. //
  1388. // QTUtils_ConvertPascalToCString
  1389. // Convert a Pascal string into a C string.
  1390. //
  1391. // The caller is responsible for disposing of the pointer returned by this function (by calling free).
  1392. //
  1393. //////////
  1394.  
  1395. char *QTUtils_ConvertPascalToCString (StringPtr theString)
  1396. {
  1397.     char         *myString = malloc(theString[0] + 1);
  1398.     short        myIndex = 0;
  1399.  
  1400.     for (myIndex = 0; myIndex < theString[0]; myIndex++)
  1401.         myString[myIndex] = theString[myIndex + 1];
  1402.     
  1403.     myString[theString[0]] = '\0';
  1404.     
  1405.     return(myString);
  1406. }
  1407.  
  1408.  
  1409. //////////
  1410. //
  1411. // QTUtils_DeleteAllReferencesToTrack
  1412. // Delete all existing track references to the specified track.
  1413. //
  1414. //////////
  1415.  
  1416. OSErr QTUtils_DeleteAllReferencesToTrack (Track theTrack)
  1417. {
  1418.     Movie                myMovie = NULL;
  1419.     Track                myTrack = NULL;
  1420.     long                myTrackCount = 0L;
  1421.     long                myTrRefCount = 0L;
  1422.     long                myTrackIndex;
  1423.     long                myTrRefIndex;
  1424.     OSErr                myErr = noErr;
  1425.  
  1426.     myMovie = GetTrackMovie(theTrack);
  1427.     if (myMovie == NULL)
  1428.         return(paramErr);
  1429.  
  1430.     // iterate thru all the tracks in the movie (that are different from the specified track)
  1431.     myTrackCount = GetMovieTrackCount(myMovie);
  1432.     for (myTrackIndex = 1; myTrackIndex <= myTrackCount; myTrackIndex++) {
  1433.         myTrack = GetMovieIndTrack(myMovie, myTrackIndex);
  1434.         if ((myTrack != NULL) && (myTrack != theTrack)) {
  1435.             OSType        myType = 0L;
  1436.     
  1437.             // iterate thru all track reference types contained in the current track
  1438.             myType = GetNextTrackReferenceType(myTrack, myType);
  1439.             while (myType != 0L) {
  1440.  
  1441.                 // iterate thru all track references of the current type;
  1442.                 // note that we count down to 1, since DeleteTrackReference will cause
  1443.                 // any higher-indexed track references to be renumbered
  1444.                 myTrRefCount = GetTrackReferenceCount(myTrack, myType);
  1445.                 for (myTrRefIndex = myTrRefCount; myTrRefIndex >= 1; myTrRefIndex--) {
  1446.                     Track    myRefTrack = NULL;
  1447.  
  1448.                     myRefTrack = GetTrackReference(myTrack, myType, myTrRefIndex);
  1449.                     if (myRefTrack == theTrack)
  1450.                         myErr = DeleteTrackReference(myTrack, myType, myTrRefIndex);
  1451.                 }
  1452.  
  1453.                 myType = GetNextTrackReferenceType(myTrack, myType);
  1454.             }
  1455.         }
  1456.     }
  1457.  
  1458.     return(myErr);
  1459. }
  1460.  
  1461.  
  1462. //////////
  1463. //
  1464. // QTUtils_GetFrameDuration
  1465. // Get the duration of the first sample frame in the specified movie track.
  1466. //
  1467. //////////
  1468.  
  1469. TimeValue QTUtils_GetFrameDuration (Track theTrack)
  1470. {    
  1471.     TimeValue    mySampleDuration;
  1472.     OSErr        myErr = noErr;
  1473.  
  1474.     myErr = GetMediaSample(    GetTrackMedia(theTrack),
  1475.                             NULL,         // don't return sample data
  1476.                             0,
  1477.                             NULL,        // don't return number of bytes of sample data returned
  1478.                             0,
  1479.                             NULL,
  1480.                             &mySampleDuration,
  1481.                             NULL,        // don't return sample description
  1482.                             NULL,        // don't return sample description index
  1483.                             0,            // no max number of samples
  1484.                             NULL,        // don't return number of samples returned
  1485.                             NULL);        // don't return sample flags
  1486.  
  1487.     // make sure we return a legitimate value even if GetMediaSample encounters an error
  1488.     if (myErr != noErr)
  1489.         mySampleDuration = 0;
  1490.  
  1491.     return(mySampleDuration);
  1492. }
  1493.  
  1494.  
  1495. //////////
  1496. //
  1497. // QTUtils_GetFrameCount
  1498. // Get the number of frames in the specified movie track. We return the value -1 if
  1499. // an error occurs and we cannot determine the number of frames in the track.
  1500. //
  1501. // Based (loosely) on frame-counting code in ConvertToMovie Jr.c.
  1502. // 
  1503. // We count the frames in the track by stepping through all of its interesting times
  1504. // (the places where the track displays a new sample).
  1505. //
  1506. //////////
  1507.  
  1508. long QTUtils_GetFrameCount (Track theTrack)
  1509. {    
  1510.     long        myCount = -1;
  1511.     short        myFlags;
  1512.     TimeValue    myTime = 0;
  1513.     
  1514.     if (theTrack == NULL)
  1515.         goto bail;
  1516.         
  1517.     // we want to begin with the first frame (sample) in the track
  1518.     myFlags = nextTimeMediaSample + nextTimeEdgeOK;
  1519.  
  1520.     while (myTime >= 0) {
  1521.         myCount++;
  1522.         
  1523.         // look for the next frame in the track; when there are no more frames,
  1524.         // myTime is set to -1, so we'll exit the while loop
  1525.         GetTrackNextInterestingTime(theTrack, myFlags, myTime, fixed1, &myTime, NULL);
  1526.         
  1527.         // after the first interesting time, don't include the time we're currently at
  1528.         myFlags = nextTimeStep;
  1529.     }
  1530.  
  1531. bail:
  1532.     return(myCount);
  1533. }
  1534.  
  1535.  
  1536. //////////
  1537. //
  1538. // QTUtils_GetMaxWindowDepth
  1539. // Get the deepest pixel type and size of the screen area intersected by a specified window.
  1540. //
  1541. //////////
  1542.  
  1543. void QTUtils_GetMaxWindowDepth (CWindowPtr theWindow, short *thePixelType, short *thePixelSize)
  1544. {
  1545.     Rect            myRect;
  1546.     Point            myPoint = {0, 0};
  1547.     
  1548.     // initialize returned values 
  1549.     *thePixelType = k1MonochromePixelFormat;
  1550.     *thePixelSize = 0;
  1551.  
  1552.     if (theWindow == NULL)
  1553.         return;
  1554.  
  1555.     myRect = theWindow->portRect;
  1556.     
  1557.     // assume the window is the current port
  1558.     LocalToGlobal(&myPoint);
  1559.  
  1560.     // offset the rectangle to global coordinates
  1561.     MacOffsetRect(&myRect, myPoint.h, myPoint.v);
  1562.     
  1563.     // get the max data for the global rectangle
  1564.     QTUtils_GetMaxScreenDepth(&myRect, thePixelType, thePixelSize);
  1565. }
  1566.  
  1567.  
  1568. //////////
  1569. //
  1570. // QTUtils_GetMaxScreenDepth
  1571. // Get the deepest pixel type and size of the screen area intersected by a specified rectangle.
  1572. //
  1573. //////////
  1574.  
  1575. void QTUtils_GetMaxScreenDepth (Rect *theGlobalRect, short *thePixelType, short *thePixelSize)
  1576. {
  1577.     GDHandle        myGDevice = NULL;
  1578.     PixMapHandle    myPixMap = NULL;
  1579.  
  1580.     myGDevice = GetMaxDevice(theGlobalRect);    // get the max device
  1581.     if (myGDevice != NULL) {
  1582.         // get the pixmap for the max device
  1583.         myPixMap = (**myGDevice).gdPMap;
  1584.         if (myPixMap != NULL) {
  1585.             // extract the interesting info from the pixmap of the device
  1586.             *thePixelType = (**myPixMap).pixelType;
  1587.             *thePixelSize = (**myPixMap).pixelSize;
  1588.         }
  1589.     }
  1590. }
  1591.  
  1592.  
  1593. //////////
  1594. //
  1595. // QTUtils_GetUsersConnectionSpeed
  1596. // Return the connection speed selected by the user in the QuickTime Settings control panel;
  1597. // return 0 if the user's QuickTime preferences cannot be read.
  1598. //
  1599. // Based on code in Ice Floe Dispatch 17 by Mike Dodd.
  1600. //
  1601. //////////
  1602.  
  1603. long QTUtils_GetUsersConnectionSpeed (void)
  1604. {
  1605.     QTAtomContainer                    myPrefsContainer = NULL;
  1606.     QTAtom                            myPrefsAtom = 0;
  1607.     ConnectionSpeedPrefsRecord        myPrefsRec;
  1608.     long                            myDataSize = 0L;
  1609.     long                            mySpeed = 0L;
  1610.     Ptr                                myAtomData = NULL;
  1611.     OSErr                            myErr = noErr;
  1612.  
  1613.     // you can retrieve the user's QuickTime preferences by calling GetQuickTimePreference;
  1614.     // the first parameter indicates the type of preference you want information about, and
  1615.     // the second parameter is an atom container that contains the returned preference data 
  1616.     myErr = GetQuickTimePreference(ConnectionSpeedPrefsType, &myPrefsContainer);
  1617.     if (myErr == noErr) {
  1618.             
  1619.         // find the atom of the desired type
  1620.         myPrefsAtom = QTFindChildByID(myPrefsContainer, kParentAtomIsContainer, ConnectionSpeedPrefsType, 1, NULL);
  1621.         if (myPrefsAtom == 0) {
  1622.             // we did not find any such atom in the returned atom container, so we'll
  1623.             // return a default connection speed setting of 28.8K bytes per second
  1624.             mySpeed = kDataRate288ModemRate;
  1625.         } else {
  1626.             // we found the desired atom in the returned atom container;
  1627.             // read the data contained in that atom and verify that the data is of the
  1628.             // size we are expecting
  1629.             QTGetAtomDataPtr(myPrefsContainer, myPrefsAtom, &myDataSize, &myAtomData);
  1630.             
  1631.             if (myDataSize != sizeof(ConnectionSpeedPrefsRecord)) {
  1632.                 // the data in the atom isn't the right size, so it must be corrupt;
  1633.                 // return a default connection speed setting of 28.8K bytes per second
  1634.                 mySpeed = kDataRate288ModemRate;
  1635.             } else {
  1636.                 // everything is fine: read the connection speed
  1637.                 
  1638.                 // NOTE: the data in this atom is native-endian, so we do not need to
  1639.                 // perform any endian-swapping when extracting the speed from the atom.
  1640.                 // (This is an exception to the rule that data in atom containers is
  1641.                 // always big-endian.)
  1642.                 myPrefsRec = *(ConnectionSpeedPrefsRecord *)myAtomData;
  1643.                 mySpeed = myPrefsRec.connectionSpeed;
  1644.             }
  1645.         }
  1646.  
  1647.         QTDisposeAtomContainer(myPrefsContainer);
  1648.     }
  1649.     
  1650.     return(mySpeed);
  1651. }
  1652.  
  1653.  
  1654. //////////
  1655. //
  1656. // QTUtils_SetUsersConnectionSpeed
  1657. // Set the connection speed in the QuickTime Settings control panel to the specified value.
  1658. //
  1659. // NOTE: In general, you should let the user decide the connection speed (using the QuickTime
  1660. // Settings control panel). In some cases, however, you might need to do this programmatically.
  1661. // Also, you should in general use values for theSpeed that are enumerated in the header file
  1662. // MoviesFormat.h.
  1663. //
  1664. // Based on code in Ice Floe Dispatch 17 by Mike Dodd.
  1665. //
  1666. //////////
  1667.  
  1668. OSErr QTUtils_SetUsersConnectionSpeed (long theSpeed)
  1669. {
  1670.     QTAtomContainer                    myPrefsContainer = NULL;
  1671.     QTAtom                            myPrefsAtom = 0;
  1672.     ConnectionSpeedPrefsRecord        myPrefsRec;
  1673.     OSErr                            myErr = noErr;
  1674.  
  1675.     myErr = QTNewAtomContainer(&myPrefsContainer);
  1676.     if (myErr == noErr) {
  1677.         // NOTE: the data in this atom is native-endian, so we do not need to
  1678.         // perform any endian-swapping when inserting the speed into the atom.
  1679.         // (This is an exception to the rule that data in atom containers is
  1680.         // always big-endian.)
  1681.         myPrefsRec.connectionSpeed = theSpeed;
  1682.         
  1683.         myErr = QTInsertChild(myPrefsContainer, kParentAtomIsContainer, ConnectionSpeedPrefsType, 1, 0, sizeof(ConnectionSpeedPrefsRecord), &myPrefsRec, &myPrefsAtom);
  1684.         if (myErr == noErr)
  1685.             myErr = SetQuickTimePreference(ConnectionSpeedPrefsType, myPrefsContainer);
  1686.             
  1687.         QTDisposeAtomContainer(myPrefsContainer);
  1688.     }
  1689.  
  1690.     return(myErr);
  1691. }
  1692.  
  1693.  
  1694. #if CONTENT_RATING_AVAIL
  1695. //////////
  1696. //
  1697. // QTUtils_GetUsersContentRating
  1698. // Return, through the function's parameters, the content rating and acceptable content types
  1699. // selected by the user in the QuickTime Settings control panel; return an error if the user's
  1700. // QuickTime preferences cannot be read.
  1701. //
  1702. // Based on QTUtils_GetUsersConnectionSpeed.
  1703. //
  1704. //////////
  1705.  
  1706. OSErr QTUtils_GetUsersContentRating (UInt32 *theType, UInt16 *theRating)
  1707. {
  1708.     QTAtomContainer                    myPrefsContainer = NULL;
  1709.     QTAtom                            myPrefsAtom = 0;
  1710.     ContentRatingPrefsRecord        myContentRec;
  1711.     long                            myDataSize = 0L;
  1712.     Ptr                                myAtomData = NULL;
  1713.     OSErr                            myErr = noErr;
  1714.  
  1715.     // you can retrieve the user's QuickTime preferences by calling GetQuickTimePreference;
  1716.     // the first parameter indicates the type of preference you want information about, and
  1717.     // the second parameter is an atom container that contains the returned preference data 
  1718.     myErr = GetQuickTimePreference(kContentRatingPrefsType, &myPrefsContainer);
  1719.     if (myErr == noErr) {
  1720.             
  1721.         // find the atom of the desired type
  1722.         myPrefsAtom = QTFindChildByID(myPrefsContainer, kParentAtomIsContainer, kContentRatingPrefsType, 1, NULL);
  1723.         if (myPrefsAtom == 0) {
  1724.             // we did not find any such atom in the returned atom container, so we'll
  1725.             // return default settings
  1726.             *theType = 0L;
  1727.             *theRating = kQTContentTVYRating;
  1728.         } else {
  1729.             // we found the desired atom in the returned atom container;
  1730.             // read the data contained in that atom and verify that the data is of the
  1731.             // size we are expecting
  1732.             myErr = QTGetAtomDataPtr(myPrefsContainer, myPrefsAtom, &myDataSize, &myAtomData);
  1733.             
  1734.             if (myDataSize != sizeof(ContentRatingPrefsRecord)) {
  1735.                 // the data in the atom isn't the right size, so it must be corrupt;
  1736.                 // return default settings
  1737.                 *theType = 0L;
  1738.                 *theRating = kQTContentTVYRating;
  1739.             } else {
  1740.                 // everything is fine: read the content information
  1741.                 
  1742.                 // NOTE: the data in this atom is native-endian, so we do not need to
  1743.                 // perform any endian-swapping when extracting the data from the atom.
  1744.                 // (This is an exception to the rule that data in atom containers is
  1745.                 // always big-endian.)
  1746.                 
  1747.                 // WARNING: the format of the data in a content rating atom is, to my
  1748.                 // knowledge, currently undocumented; the following method of extracting
  1749.                 // that info is based on empirical investigation.
  1750.                 myContentRec = *(ContentRatingPrefsRecord *)myAtomData;
  1751.                 *theType = (UInt32)(~(myContentRec.fContentTypes) & 0x00ff);
  1752.                 *theRating = myContentRec.fContentRating;
  1753.             }
  1754.         }
  1755.  
  1756.         QTDisposeAtomContainer(myPrefsContainer);
  1757.     }
  1758.     
  1759.     return(myErr);
  1760. }
  1761. #endif    // #if CONTENT_RATING_AVAIL
  1762.  
  1763.  
  1764. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1765. //
  1766. // Controller utilities.
  1767. //
  1768. // Use these functions to manipulate movie controllers.
  1769. //
  1770. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  1771.  
  1772. //////////
  1773. //
  1774. // QTUtils_GetControllerType
  1775. // Get the controller type of the specified movie.
  1776. //
  1777. //////////
  1778.  
  1779. OSType QTUtils_GetControllerType (Movie theMovie) 
  1780. {
  1781.     UserData        myUserData;
  1782.     OSType            myType = kQTVRUnknownType;
  1783.     
  1784.     // make sure we've got a movie
  1785.     if (theMovie == NULL)
  1786.         return(myType);
  1787.         
  1788.     myUserData = GetMovieUserData(theMovie);
  1789.     if (myUserData != NULL)
  1790.         GetUserDataItem(myUserData, &myType, sizeof(myType), kUserDataMovieControllerType, 0);
  1791.     
  1792.     return(EndianU32_BtoN(myType));
  1793. }
  1794.  
  1795.  
  1796. //////////
  1797. //
  1798. // QTUtils_SetControllerType
  1799. // Set the controller type of the specified movie.
  1800. //
  1801. // This function adds an item to the movie's user data;
  1802. // the updated user data is written to the movie file when the movie is next updated
  1803. // (by calling AddMovieResource or UpdateMovieResource).
  1804. //
  1805. // NOTE: This function is intended to set the controller type of a movie you're building;
  1806. // to change the controller of an open movie, use QTUtils_ChangeControllerType.
  1807. //
  1808. //////////
  1809.  
  1810. OSErr QTUtils_SetControllerType (Movie theMovie, OSType theType)
  1811. {
  1812.     UserData        myUserData;
  1813.     OSErr            myErr = noErr;
  1814.  
  1815.     // make sure we've got a movie
  1816.     if (theMovie == NULL)
  1817.         return(paramErr);
  1818.         
  1819.     // get the movie's user data list
  1820.     myUserData = GetMovieUserData(theMovie);
  1821.     if (myUserData == NULL)
  1822.         return(paramErr);
  1823.     
  1824.     theType = EndianU32_NtoB(theType);
  1825.     myErr = SetUserDataItem(myUserData, &theType, sizeof(theType), kUserDataMovieControllerType, 0);
  1826.  
  1827.     return(myErr);
  1828. }
  1829.  
  1830.  
  1831. //////////
  1832. //
  1833. // QTUtils_ChangeControllerType
  1834. // Change the controller type of the movie that uses the specified controller, "on the fly",
  1835. // and return the new movie controller to the caller; if for some reason we cannot create a
  1836. // new movie controller, return NULL.
  1837. //
  1838. //////////
  1839.  
  1840. MovieController QTUtils_ChangeControllerType (MovieController theMC, OSType theType, long theFlags)
  1841. {
  1842.     MovieController        myMC = NULL;
  1843.     Movie                myMovie = NULL;
  1844.     Rect                myRect;
  1845.     OSErr                myErr = noErr;
  1846.  
  1847.     // make sure we've got a movie controller
  1848.     if (theMC == NULL)
  1849.         return(NULL);
  1850.     
  1851.     // get the movie associated with that controller
  1852.     myMovie = MCGetMovie(theMC);
  1853.     if (myMovie == NULL)
  1854.         return(NULL);
  1855.         
  1856.     GetMovieBox(myMovie, &myRect);
  1857.  
  1858.     // set the new controller type in the movie's user data list
  1859.     myErr = QTUtils_SetControllerType(myMovie, theType);
  1860.     if (myErr != noErr)
  1861.         return(NULL);
  1862.  
  1863.     // dispose of the existing controller
  1864.     DisposeMovieController(theMC);
  1865.     
  1866.     // create a new controller of the specified type
  1867.     myMC = NewMovieController(myMovie, &myRect, theFlags);
  1868.  
  1869.     return(myMC);
  1870. }
  1871.  
  1872.  
  1873. #endif    // ifndef __QTUtilities__